當我們從比較 Low-Level 的角度而非套件包裝好的角度看函式操作時,會發現其實我們只是送出一筆交易,其中 to:
是 contractAddress
,而 data:
是 contractFX_encodeABI
。想必 contractAddress
是非常好理解,但什麼是 contractFX_encodeABI
其實對初學者來說並不是那麼的直觀!
contractFX_encodeABI
其實就是一個 ABI Byte String,在說明他可以拿來做什麼之前,我們先來看看要怎麼得到它。假設我們在一個合約中有一個函式 myUint()
,那要得到它的 ABI Byte String 有幾種方法:
myUint()
那個按鈕,就可以在 console window 的 call 得到它的回傳值:
input field: "0x06540f7e"
Return: "0x06540f7e"
06540f7e
web3.eth.<myContract>.methods.myUint().encodeABI()
這個 Function 的完整字串實際上也就是所謂的 Function Signature,而哈希過後得到的 ABI Byte String 便是 Function Selector。
我們來看看編譯完之後產生的 Bytecode 中的 oject,會發現 06540f7e
就存在其中:
{
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "60...06540f7e...33",
"opcodes": "PUSH1 0x80 ... ",
"sourceMap": "..."
}
這也就是為什麼我們在傳送交易和合約函式進行互動時,可以透過傳入 Function Signature 並 encoded 後,執行相對應的函式,因為它就藏在合約地址裡面的 Bytecode(data field) 中。
函式簽章(Function Signature)
function myUint()
bytes4(keccak256("myUint()"));
function someFunction(uint _myUint1, address _someAddr)
bytes4(keccak256("someFunction(uint256,address)"))
前面介紹了如何從合約外部呼叫合約函式(交易或者前端),那我們要怎麼從合約裡面用上 Function Signature 呼叫合約函式呢?實際上和前面的做法一模一樣,也就是將 Function Signature 進行 Hash 之後取其回傳的 hex 的前 4 bytes 送給 EVM,這個結果又稱作 Function Selector。
轉換的過程如下:
contract Convert {
/**
* @dev This function encodes a function signature and returns it.
* @notice There are no spaces between the parameters types, and the
* parameters names are not included when encoding.
* @return bytes4 : The encoded function signature -> function selector.
*/
function getSelector(string calldata _funcSig) public(bytes4) {
return bytes4(keccak256(bytes(_funcSig)));
}
}
還記得我們之前提到過的 call
嗎,這邊我們一樣是使用它來呼叫函式(當然你也可以直接呼叫它的名子):
contract callFx {
function execute(bytes _parameters) public {
require(
this.call(
bytes4(keccak256("myFunc(string,uint256)")), _parameters),
"Execution Failed"
);
}
}
需要注意的是 call() 這個呼叫最好要包在 require() 裡面,因為 call() 的成功與否是回傳一個 boolean 而不是彈出錯誤,所以如果沒有用 require() 包起來的話發生錯誤時我們並不會發現!
備註一下 interface,以下兩種方法是相同的:
bytes4(keccak256(“onERC721Received(address,address,uint256,bytes)”))
IERC721Receiver(0).onERC721Received.selector
推薦大家看看這個工具,如果知道這個工具怎麼用代表你懂 Function Selector 之中的秘密了。
最後歡迎大家拍打餵食大學生
0x2b83c71A59b926137D3E1f37EF20394d0495d72d